/*
 * This file is part of "Deathwatch Ammo Counter for Android".
 *
 * "Deathwatch Ammo Counter for Android" is free software: you can redistribute
 * it and/or modify it under the terms of the GNU General Public License as 
 * published by the Free Software Foundation, either version 3 of the License, 
 * or (at your option) any later version.
 *
 * "Deathwatch Ammo Counter for Android" is distributed in the hope that it 
 * will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty 
 * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General 
 * Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with "Deathwatch Ammo Counter for Android".  
 * If not, see <http://www.gnu.org/licenses/>.
 * 
 */
package com.TikiiTorch.Deathwatch.AmmoCounter.file;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;

import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;

import org.xml.sax.InputSource;
import org.xml.sax.SAXException;
import org.xml.sax.XMLReader;
import org.xmlpull.v1.XmlSerializer;

import android.content.Context;
import android.os.Environment;
import android.util.Log;
import android.util.Xml;
import android.widget.Toast;

import com.TikiiTorch.Deathwatch.AmmoCounter.AmmoLoad;
import com.TikiiTorch.Deathwatch.AmmoCounter.Ammunition;
import com.TikiiTorch.Deathwatch.AmmoCounter.C;
import com.TikiiTorch.Deathwatch.AmmoCounter.SpaceMarine;
import com.TikiiTorch.Deathwatch.AmmoCounter.Weapon;

public class FileManager {

	/**
	 * The directory to the character files
	 */
	private static final String CHAR_XML_DIR = "/TikiiTorch/ammoCounter/";

	/**
	 * Determines if the directory that holds the character XML files actually
	 * contains a file or not
	 * 
	 * @return True if there is at least one character XML; False otherwise
	 */
	public static boolean charXMLExists() {

		File dir = new File(Environment.getExternalStorageDirectory()
				.getAbsolutePath() + CHAR_XML_DIR);

		File[] contents = dir.listFiles();

		if (contents == null) {
			// directory is empty
			return false;
		} else {
			return true;
		}
	}

	/**
	 * Creates the directory to store the character XML files. This should
	 * happen once - at first launch
	 */
	public static void createCharXMLDir() {
		File sdCard = Environment.getExternalStorageDirectory();
		File dir = new File(sdCard.getAbsolutePath() + CHAR_XML_DIR);

		dir.mkdirs();
	}

	public static void saveSpaceMarineFile(Context context, SpaceMarine marine) {

		// String name = "newFile";
		String name = marine.getName();

		File outFile = getCharFile(name);

		Log.d(C.TAG, "Attempting to save file: " + outFile.toString());

		try {
			outFile.createNewFile();
		} catch (IOException ex) {
			Toast.makeText(context, "Error saving character file!",
					Toast.LENGTH_SHORT);
			Log.e(C.TAG, "IOException in creating file for character: "
					+ marine.getName());
			ex.printStackTrace();
		}

		// bind file with output stream
		FileOutputStream fos = null;
		try {
			fos = new FileOutputStream(outFile);
		} catch (FileNotFoundException ex) {
			Toast.makeText(context, "Error saving character file!",
					Toast.LENGTH_SHORT);
			Log.e(C.TAG, "FileNotFound in creating file for character: "
					+ marine.getName());
			ex.printStackTrace();
		}

		// create XMLSerializer to write data with
		XmlSerializer out = Xml.newSerializer();
		try {

			out.setOutput(fos, "UTF-8");
			// Write <?xml declaration with encoding (if encoding not null) and
			// standalone flag (if standalone not null)
			out.startDocument(null, Boolean.valueOf(true));
			// set indentation option
			out.setFeature(
					"http://xmlpull.org/v1/doc/features.html#indent-output",
					true);

			out.startTag(null, "character");
			out.attribute(null, "name", marine.getName());

			for (Weapon w : marine.getWeapons()) {
				out.startTag(null, "weapon");

				out.startTag(null, "weaponName");
				out.text(w.getName());
				out.endTag(null, "weaponName");

				out.startTag(null, "rof");
				String rofString = "";
				for (int i = 0; i < w.getROF().length; i++) {
					rofString = rofString + w.getROF()[i];
					if (!(i + 1 == w.getROF().length))
						rofString = rofString + ",";
				}
				out.text(rofString);
				out.endTag(null, "rof");

				out.startTag(null, "weaponType");
				out.text(w.getAmmoType());
				out.endTag(null, "weaponType");

				out.startTag(null, "clipSize");
				out.text(String.valueOf(w.getClipSize()));
				out.endTag(null, "clipSize");

				out.startTag(null, "ammoSupply");

				for (AmmoLoad a : w.getAmmoLoads()) {
					out.startTag(null, "ammo");
					out.attribute(null, "name", a.getName());

					out.startTag(null, "effect");
					out.text(a.getEffect());
					out.endTag(null, "effect");

					out.startTag(null, "inClip");
					out.text(String.valueOf(a.getClipAmount()));
					out.endTag(null, "inClip");

					out.startTag(null, "inBag");
					out.text(String.valueOf(a.getBagAmount()));
					out.endTag(null, "inBag");

					out.endTag(null, "ammo");
				}

				out.endTag(null, "ammoSupply");

				out.endTag(null, "weapon");
			}

			out.endTag(null, "character");

			out.endDocument();

			// write xml data into the FileOutputStream
			out.flush();
			// finally we close the file stream
			fos.close();

		} catch (Exception ex) {
			Toast.makeText(context, "Error saving character file!",
					Toast.LENGTH_SHORT);
			Log.e(C.TAG,
					"Exception in creating file for character: "
							+ marine.getName());
			ex.printStackTrace();
		}
	}

	/**
	 * Gets a list of saved characters. This list will not be accurate if the
	 * files in the character directory have been altered. This only uses the
	 * directory contents to build a list. As the character directory is hidden,
	 * this should be safe enough.
	 * 
	 * @return A String array of the character names
	 */
	public static String[] getCharList() {

		File dir = new File(Environment.getExternalStorageDirectory()
				.getAbsolutePath() + CHAR_XML_DIR);

		File[] contents = dir.listFiles();

		String[] charList = new String[contents.length];

		for (int i = 0; i < contents.length; i++) {

			String fileName = contents[i].getName();

			String charName = fileName.substring(0,
					fileName.lastIndexOf(".xml"));

			charList[i] = charName;

		}

		return charList;

	}

	/**
	 * Reads a character XMl file, constructs a SpaceMarine object from the file
	 * contents and returns that object
	 * 
	 * @param name
	 *            The character name (this is also the file name)
	 * @return A SpaceMarine object based on the file contents
	 * @throws SAXException
	 * @throws ParserConfigurationException
	 * @throws FileNotFoundException
	 * @throws IOException
	 */
	public static SpaceMarine getSpaceMarine(String name) throws SAXException,
			ParserConfigurationException, FileNotFoundException, IOException {

		File charFile = getCharFile(name);

		SAXParserFactory parserFactory = SAXParserFactory.newInstance();
		SAXParser saxParser = parserFactory.newSAXParser();
		XMLReader reader = saxParser.getXMLReader();
		SpaceMarineHandler handler = new SpaceMarineHandler();
		reader.setContentHandler(handler);
		reader.parse(new InputSource(new InputStreamReader(new FileInputStream(
				charFile))));

		return handler.getSpaceMarine();

	}

	/**
	 * Gets a list of the ammunition types that can be used with a weapon of
	 * type {@code gunType}
	 * 
	 * @param context
	 *            The context
	 * @param gunType
	 *            The ammo type to match
	 * @return A list of usable ammo types
	 * @throws IOException
	 * @throws ParserConfigurationException
	 * @throws SAXException
	 */
	public static Ammunition[] getAmmunitionList(Context context, String gunType)
			throws IOException, ParserConfigurationException, SAXException {

		InputSource is = new InputSource(context.getAssets().open(
				"ammo_types.xml"));

		// create the SAX factory
		SAXParserFactory factory = SAXParserFactory.newInstance();

		// create parser
		SAXParser parser = factory.newSAXParser();

		// create reader (scanner)
		XMLReader xmlReader = parser.getXMLReader();

		// instantiate handler
		AmmoHandler handler = new AmmoHandler(gunType);
		xmlReader.setContentHandler(handler);

		xmlReader.parse(is);

		return handler.getMatches();

	}

	public static Weapon[][] getWeaponList(Context context) throws IOException,
			ParserConfigurationException, SAXException {

		InputSource is = new InputSource(context.getAssets().open(
				"weapon_types.xml"));

		// create the SAX factory
		SAXParserFactory factory = SAXParserFactory.newInstance();

		// create parser
		SAXParser parser = factory.newSAXParser();

		// create reader (scanner)
		XMLReader xmlReader = parser.getXMLReader();

		// instantiate handler
		WeaponHandler handler = new WeaponHandler(context);
		xmlReader.setContentHandler(handler);

		xmlReader.parse(is);

		return handler.getWeapons();

	}

	public static void deleteCharFile(String name) {
		File file = getCharFile(name);

		file.delete();
	}

	/**
	 * Creates the absolute pathname for the character file with name
	 * {@code name}
	 * 
	 * @param name
	 *            The name of the character
	 * @return The absolute pathname for the character file with name
	 *         {@code name}
	 */
	private static File getCharFile(String name) {
		String fileName = name + ".xml";

		File file = new File(Environment.getExternalStorageDirectory()
				.getAbsolutePath() + CHAR_XML_DIR + fileName);

		return file;
	}

}
